package com.cap6402.project.two;

import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import java.util.Set;

import org.andengine.audio.music.Music;
import org.andengine.audio.music.MusicFactory;
import org.andengine.audio.sound.Sound;
import org.andengine.audio.sound.SoundFactory;
import org.andengine.engine.camera.ZoomCamera;
import org.andengine.engine.camera.hud.HUD;
import org.andengine.engine.handler.IUpdateHandler;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.FillResolutionPolicy;
import org.andengine.entity.Entity;
import org.andengine.entity.IEntity;
import org.andengine.entity.primitive.Line;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.andengine.entity.scene.background.SpriteBackground;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.text.Text;
import org.andengine.entity.text.Text.TextOptions;
import org.andengine.entity.util.FPSLogger;
import org.andengine.input.touch.TouchEvent;
import org.andengine.input.touch.detector.PinchZoomDetector;
import org.andengine.input.touch.detector.SurfaceScrollDetector;
import org.andengine.input.touch.detector.PinchZoomDetector.IPinchZoomDetectorListener;
import org.andengine.input.touch.detector.ScrollDetector;
import org.andengine.input.touch.detector.ScrollDetector.IScrollDetectorListener;
import org.andengine.opengl.font.Font;
import org.andengine.opengl.font.FontFactory;
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.atlas.bitmap.source.EmptyBitmapTextureAtlasSource;
import org.andengine.opengl.texture.atlas.bitmap.source.IBitmapTextureAtlasSource;
import org.andengine.opengl.texture.atlas.bitmap.source.decorator.BaseBitmapTextureAtlasSourceDecorator;
import org.andengine.opengl.texture.bitmap.BitmapTexture;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.texture.region.TextureRegionFactory;
import org.andengine.opengl.vbo.VertexBufferObjectManager;
import org.andengine.ui.activity.SimpleBaseGameActivity;
import org.andengine.util.HorizontalAlign;
import org.andengine.util.adt.io.in.IInputStreamOpener;
import org.andengine.util.color.Color;
import org.andengine.util.debug.Debug;
import org.andengine.util.modifier.IModifier.DeepCopyNotSupportedException;
import org.jgrapht.DirectedGraph;
import org.jgrapht.alg.CycleDetector;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
import android.util.Log;
import android.widget.Toast;

public class SocialNetworkActivity extends SimpleBaseGameActivity implements IOnSceneTouchListener,IPinchZoomDetectorListener,IScrollDetectorListener {
    String[] permissions = { "offline_access", "publish_stream", "user_photos", "publish_checkins",
    "photo_upload" };
    
    //Scene Camera Width & Height
	private static final int CAMERA_WIDTH = 1280;
	private static final int CAMERA_HEIGHT = 800;
	private static final int CUSTOM_FRIEND_LIMIT = 100;
	
	//Game Scene
	private final Scene scene = new Scene();
	//Camera (supports multitouch zooming)
	private ZoomCamera mZoomCamera;
	final Random random = new Random();
	
	//For when we need to do UI stuff
	Handler mHandler = new Handler();
	
	//Internal Graph Representation of user's "Social Network"
	DirectedGraph<Friend,DefaultEdge> socialNetwork = new DefaultDirectedGraph<Friend,DefaultEdge>(DefaultEdge.class);
	//Maps User IDs to "Friends"
	final HashMap<String,Friend> friends = new HashMap<String,Friend>();
	//Maps Pictures to "Friends"
	final HashMap<Sprite,Friend> sprites = new HashMap<Sprite,Friend>();
	//Maps Lines to Edges in graph
	final HashMap<Line,DefaultEdge> linesToEdge = new HashMap<Line,DefaultEdge>();
	final HashMap<Friend,SoftReference<Bitmap>> friendToPic = new HashMap<Friend,SoftReference<Bitmap>>();
	//JSON Array of all user's friends
	JSONArray myFriends;
	//How many friends does user have?
	int totalFriends;
	//Me's a friend too
	Friend me;
	//What's my User ID
	private String myId;
	//Who is currently selected?
	private Sprite currentlySelected = null;
	//List of edges currently selected... possibly redudant since subgraph contains this info
	ArrayList<DefaultEdge> selected = new ArrayList<DefaultEdge>();
	//Selected Lines
	ArrayList<Line> selectedLines = new ArrayList<Line>();
	//Currently Selected subgraph
	DirectedGraph<Friend,DefaultEdge> subGraph = new DefaultDirectedGraph<Friend,DefaultEdge>(DefaultEdge.class);
	//Can't resist that facebook pop sound
	private Sound mFacebookPopSound;
	
	SpriteBackground bg;
	
	//Progress Dialog
	ProgressDialog progressDialog;
	
	//Thread to load the graph
	ProgressThread progressThread;
	
	//graph loaded yet?
	boolean everythingLoaded = false;
	
	//Timer
	Text mTimer;
	float time = 60.0f;
	
	//Score
	Text mScore;
	int score = 0;
	DecimalFormat myFormatter = new DecimalFormat("###,###");
	
	private HUD mHud = new HUD();
	//who's graph are we playing?
	String player;

	
	
	/*
	 * Layers
	 * Not sure if frontLayer being used any more
	 */
	Entity frontLayer = new Entity();
	Entity backLayer = new Entity();
	
	ArrayList<BitmapTextureAtlas> textures = new ArrayList<BitmapTextureAtlas>();
	
	private float mPinchZoomStartedCameraZoomFactor;
	private PinchZoomDetector mPinchZoomDetector;
	private SurfaceScrollDetector mScrollDetector;
	private Music myMusic;
	
	/*
	 * Called when App is first opened.
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Bundle extras = getIntent().getExtras(); 
		player = extras.getString("user");
		if(!Utility.mFacebook.isSessionValid()) {
			Log.e("Social Network","Something went wrong... facebook session should be valid");
			this.finish();
		}
		showDialog(Utility.LOAD_GAME_DIALOG);	
		//requestUserData();
	}
	
	@Override
    protected Dialog onCreateDialog(int id) {
        switch(id) {
        case Utility.LOAD_GAME_DIALOG:
            progressDialog = new ProgressDialog(SocialNetworkActivity.this);
            progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
            progressDialog.setMessage("Loading Social Network...");
            progressDialog.setCancelable(false);
            return progressDialog;
        default:
            return null;
        }
    }
	
    @Override
    protected void onPrepareDialog(int id, Dialog dialog) {
        switch(id) {
        case Utility.LOAD_GAME_DIALOG:
            progressDialog.setProgress(0);
            progressThread = new ProgressThread(handler);
            progressThread.start();
        break;
        }
    }
    
    final Handler handler = new Handler() {
    	public void handleMessage(Message msg) {
    		int state = msg.arg1;
    		if(everythingLoaded) {
    			dismissDialog(Utility.LOAD_GAME_DIALOG);
    			progressThread.setState(ProgressThread.STATE_DONE);
    		}
    	}
    };
	private Font mFont;
	private BitmapTexture mTexture;
	private ITextureRegion mTextureRegion;

	private Sound cycleFoundSound;
	
	
	/*
	 * Get "me's" friends and "me's" profile pic
	 */
    public void requestUserData() {
        Bundle params = new Bundle();
        params.putString("fields", "name,id,picture");
    	Utility.mAsyncRunner.request(player+"/friends", params,new FriendsRequestListener());
    	 
    	 String url = "https://graph.facebook.com/" + player + "/picture?type=large&access_token="+Utility.mFacebook.getAccessToken();
    	 new GetMyPicAsyncTask().execute(url);
    }
    /*
     * Setup GameEngine
     * Screen is always landscape, content fills entire screen
     * GameEngine needs sound
     */
	@Override
	public EngineOptions onCreateEngineOptions() {
		this.mZoomCamera = new ZoomCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
		EngineOptions options = new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new FillResolutionPolicy(), this.mZoomCamera);
		options.getAudioOptions().setNeedsSound(true);
		options.getAudioOptions().setNeedsMusic(true);
		return options;
	}

	/*
	 * Loads resources needed by App
	 */
	@Override
	protected void onCreateResources() {
		 SoundFactory.setAssetBasePath("mfx/");
         try {
                 this.mFacebookPopSound = SoundFactory.createSoundFromAsset(this.mEngine.getSoundManager(), this, "fbookpop.mp3");
                 this.cycleFoundSound = SoundFactory.createSoundFromAsset(this.mEngine.getSoundManager(), this, "word_twinkle.ogg");
         } catch (final IOException e) {
        	 e.printStackTrace();
         }
         MusicFactory.setAssetBasePath("mfx/");
         try {
         	this.myMusic = MusicFactory.createMusicFromAsset(this.mEngine.getMusicManager(), this, "socialnetwork.ogg");
         	this.myMusic.setLooping(true);
         } catch (final IOException e) {
         	e.printStackTrace();
         }
         
 		this.mFont = FontFactory.create(this.getFontManager(), this.getTextureManager(), 256, 256, Typeface.create(Typeface.DEFAULT, Typeface.BOLD), 32);
 		this.mFont.load();
 		
		try {
			IInputStreamOpener iinputStreamOpener = new IInputStreamOpener() {
				@Override
				public InputStream open() throws IOException {
					return getAssets().open("gfx/bg.jpg");
				}
			};
			this.mTexture = new BitmapTexture(this.getTextureManager(), iinputStreamOpener);

			this.mTexture.load();
			this.mTextureRegion = TextureRegionFactory.extractFromTexture(this.mTexture);
		} catch (IOException e) {
			Debug.e(e);
		}
	}
    
    @Override
    public void onPause() {
    	super.onPause();
    	if(myMusic != null && myMusic.isPlaying())
    		myMusic.pause();
    }
    
    @Override
    public void onResume() {
    	super.onResume();
    	if(myMusic != null && !myMusic.isPlaying())
    		myMusic.play();
    }
    
    /*
     * Initialize the scene
     */
	@Override
	protected Scene onCreateScene() {
		this.mEngine.registerUpdateHandler(new FPSLogger());
		this.scene.registerUpdateHandler(new IUpdateHandler() {
			@Override
			public void onUpdate(float pSecondsElapsed) {
				if(everythingLoaded) {
					mScore.setText("Score: " + myFormatter.format(score));
					if(time >= 60.0) {
						mTimer.setText("Time: 1:00");
					} else if(time >= 10 && time < 60.0){
						mTimer.setText("Time: 0:"+(int)time);
					} else if (time < 10) {
						mTimer.setText("Time: 0:0"+(int)time);
					}
					
					time -= pSecondsElapsed;
					if(time <= 0) {
						Intent intent = new Intent(SocialNetworkActivity.this, GameFinishedActivity.class);
						intent.putExtra("score", myFormatter.format(score));
						intent.putExtra("level", player);
						intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
						startActivity(intent);
						SocialNetworkActivity.this.finish();
					}
				}
			}

			@Override
			public void reset() {
				// TODO Auto-generated method stub

			}});
		Sprite sprite = new Sprite(0, 0, this.mTextureRegion, this.getVertexBufferObjectManager());
		bg = new SpriteBackground(sprite);
		scene.setBackground(bg);
		final VertexBufferObjectManager vertexBufferObjectManager = this.getVertexBufferObjectManager();
		this.mTimer = new Text(10, 10, this.mFont, "Time: 1:00", new TextOptions(HorizontalAlign.LEFT), vertexBufferObjectManager);
		this.mScore = new Text(1000,10,this.mFont,"Score: 0", "Score: XXXXXXXXXXXXXXXX".length(), new TextOptions(HorizontalAlign.LEFT),vertexBufferObjectManager);
		this.scene.setOnSceneTouchListener(this);
		this.mPinchZoomDetector = new PinchZoomDetector(this);
		this.mScrollDetector = new SurfaceScrollDetector(this);
		this.mHud.attachChild(mTimer);
		this.mHud.attachChild(mScore);
		this.mZoomCamera.setHUD(this.mHud);
		this.scene.attachChild(backLayer);
		this.scene.attachChild(frontLayer);
		
		
		return scene;
	}
	
	/*
	 * Gotta have touch
	 */
	@Override
	public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {

		this.mPinchZoomDetector.onTouchEvent(pSceneTouchEvent);
		
		if(this.mPinchZoomDetector.isZooming()) {
			this.mScrollDetector.setEnabled(false);
		} else {
			if(pSceneTouchEvent.isActionDown()) {
				this.mScrollDetector.setEnabled(true);
			}
			this.mScrollDetector.onTouchEvent(pSceneTouchEvent);
		}

		return true;
	}
	
	@Override
	public void onPinchZoomStarted(final PinchZoomDetector pPinchZoomDetector, final TouchEvent pTouchEvent) {
		for(int i = 0; i < scene.getChildCount(); i++) {
			IEntity entity = scene.getChild(i);
			if(entity.getClass().getName().equals("org.andengine.entity.primitive.Line"))
			{
				Line line = (Line) entity;
				line.setColor(Color.BLACK);
				line.setAlpha(0.2f);
				line.setVisible(true);
			}
		}
		selected.clear();
		if(currentlySelected != null)
			currentlySelected.setScale(1.0f);
		currentlySelected = null;
		this.mPinchZoomStartedCameraZoomFactor = this.mZoomCamera.getZoomFactor();
	}


	public void connectStuff() {
		Object[] edges = socialNetwork.edgeSet().toArray();
		myMusic.play();
		for(int i = 0; i < edges.length; i++) {
			DefaultEdge edge = (DefaultEdge) edges[i];
			Friend friend1 = socialNetwork.getEdgeSource(edge);
			Friend friend2 = socialNetwork.getEdgeTarget(edge);
			Sprite f1 = friend1.getPicture();
			Sprite f2 = friend2.getPicture();
        	final Line line = new Line(f1.getX()+f1.getWidth()/2.0f, f1.getY()+f1.getHeight()/2.0f, f2.getX()+f2.getWidth()/2.0f, f2.getY()+f2.getHeight()/2.0f, 2.0f, getVertexBufferObjectManager());
        	line.setColor(Color.BLACK);
        	line.setAlpha(0.2f);
        	friend1.addEdge(line);
        	friend2.addEdge(line);
        	linesToEdge.put(line, edge);
        	scene.attachChild(line);
		}
		String query = "SELECT uid1, uid2 FROM friend " +
				"WHERE uid1 IN " +
				"(SELECT uid2 FROM friend WHERE uid1=" + myId + ")" +
				"AND uid2 IN " +
				"(SELECT uid2 FROM friend WHERE uid1=" + myId +")";
        Bundle params = new Bundle();
        params.putString("method", "fql.query");
        params.putString("query", query);
        Utility.mAsyncRunner.request(null, params, new FQLRequestListener());
	}
	

	
	

	@Override
	public void onPinchZoom(final PinchZoomDetector pPinchZoomDetector, final TouchEvent pTouchEvent, final float pZoomFactor) {
		this.mZoomCamera.setZoomFactor(this.mPinchZoomStartedCameraZoomFactor * pZoomFactor);
	}

	@Override
	public void onPinchZoomFinished(final PinchZoomDetector pPinchZoomDetector, final TouchEvent pTouchEvent, final float pZoomFactor) {
		this.mZoomCamera.setZoomFactor(this.mPinchZoomStartedCameraZoomFactor * pZoomFactor);
	}
	@Override
	public void onScrollStarted(final ScrollDetector pScollDetector, final int pPointerID, final float pDistanceX, final float pDistanceY) {
		final float zoomFactor = this.mZoomCamera.getZoomFactor();
		this.mZoomCamera.offsetCenter(-pDistanceX / zoomFactor, -pDistanceY / zoomFactor);
	}

	@Override
	public void onScroll(final ScrollDetector pScollDetector, final int pPointerID, final float pDistanceX, final float pDistanceY) {
		final float zoomFactor = this.mZoomCamera.getZoomFactor();
		this.mZoomCamera.offsetCenter(-pDistanceX / zoomFactor, -pDistanceY / zoomFactor);
	}
	
	@Override
	public void onScrollFinished(final ScrollDetector pScollDetector, final int pPointerID, final float pDistanceX, final float pDistanceY) {
		final float zoomFactor = this.mZoomCamera.getZoomFactor();
		this.mZoomCamera.offsetCenter(-pDistanceX / zoomFactor, -pDistanceY / zoomFactor);
	}
	
	/*
	 * Callback for getting FQL Query Result
	 * 
	 */
	public class FQLRequestListener extends BaseRequestListener {

		@Override
		public void onComplete(String response, Object state) {
			// TODO Auto-generated method stub
			JSONArray json = null;
			try {
				json = new JSONArray(response);
			} catch (JSONException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			for(int i = 0; i < json.length(); i++) {
				JSONObject object;
				try {
					object = json.getJSONObject(i);
					final String friend = object.getString("uid1");
					final String friendInCommon = object.getString("uid2");
					if(!friends.containsKey(friend) || !friends.containsKey(friendInCommon)){
						continue;
					}
					final Friend f1 = friends.get(friend);
					final Friend f2 = friends.get(friendInCommon);
					synchronized(socialNetwork) {
				if(socialNetwork.containsEdge(f1,f2))
						continue;
					}
					 mHandler.post(new Runnable() {
			                @Override
			                public void run() {
			                	Sprite pic1 = f1.getPicture();
			                	Sprite pic2 = f2.getPicture();
			                	synchronized(socialNetwork) {
			                		socialNetwork.addEdge(friends.get(friend), friends.get(friendInCommon));
			                		socialNetwork.addEdge(friends.get(friendInCommon), friends.get(friend));
			                	}
					        	final Line line = new Line(pic1.getX()+pic1.getWidth()/2.0f, pic1.getY()+pic1.getHeight()/2.0f, pic2.getX()+pic2.getWidth()/2.0f, pic2.getY()+pic2.getHeight()/2.0f, 2.0f, getVertexBufferObjectManager());
					        	line.setColor(Color.BLACK);
					        	line.setAlpha(0.2f);
					        	DefaultEdge edge = socialNetwork.getEdge(friends.get(friend), friends.get(friendInCommon));
					        	synchronized(linesToEdge) {
					        		linesToEdge.put(line, edge);
					        	}
					        	f1.addEdge(line);
					        	f2.addEdge(line);
					        	scene.attachChild(line);
			                }
			            });
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
			everythingLoaded = true;
		}
		
	}
	
    /*
     * Callback for fetching current user's friends
     */
    public class FriendsRequestListener extends BaseRequestListener {
    	@Override
    	public void onComplete(final String response, final Object state) {
    		JSONObject jsonObject;
    		try {
    			jsonObject = new JSONObject(response);
    			JSONArray jsonArray = jsonObject.getJSONArray("data");
    			jsonArray = Utility.shuffle(jsonArray);
    			myFriends = jsonArray;
    			if(jsonArray.length() < CUSTOM_FRIEND_LIMIT){
    				totalFriends = jsonArray.length();
    			}else{
        			totalFriends = CUSTOM_FRIEND_LIMIT;
    			}
    			for(int i = 0; i < totalFriends; i++) {		
    				final JSONObject friend = jsonArray.getJSONObject(i);
    				new GetProfilePicAsyncTask().execute(friend.getString("picture"),friend.getString("id"));
    			}
    		} catch(JSONException e) {
    			e.printStackTrace();
    		}
    	}
    }

    /*
     * Async Task to get Profile Pic for friend
     */
    private class GetProfilePicAsyncTask extends AsyncTask<Object, Void, Bitmap> {
        String uid;

        @Override
        protected Bitmap doInBackground(Object... params) {
        	Bitmap mBitmap = null;
        	Bitmap targetBitmap = null;
            final String url = (String) params[0];
            this.uid = (String) params[1];
            URL img_value = null;
            try {
            	img_value = new URL(url);
            } catch (MalformedURLException e1) {
            	// TODO Auto-generated catch block
            	e1.printStackTrace();
            }
            try {
            	URLConnection connection = img_value.openConnection();
            	mBitmap = BitmapFactory.decodeStream(connection.getInputStream());
                int targetWidth = 50;
                int targetHeight = 50;
                targetBitmap = Bitmap.createBitmap(
                    targetWidth,
                    targetHeight,
                    Bitmap.Config.ARGB_8888);
                Canvas canvas = new Canvas(targetBitmap);
                final Paint paint = new Paint();
                paint.setStrokeWidth(5);
                paint.setStyle(Paint.Style.STROKE);
                paint.setColor(android.graphics.Color.GRAY);
                paint.setAntiAlias(true);
                paint.setDither(true);
                Path path = new Path();
                path.addCircle(
                    ((float)targetWidth - 1) / 2,
                    ((float)targetHeight - 1) / 2,
                    (Math.min(((float)targetWidth), ((float)targetHeight)) / 2),
                    Path.Direction.CCW);
                canvas.clipPath(path);
                canvas.drawBitmap(
                    mBitmap,
                    new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight()),
                    new Rect(0, 0, targetWidth, targetHeight),
                    null);
                canvas.drawCircle(((float)targetWidth - 1) / 2,
                        ((float)targetHeight - 1) / 2,
                        (Math.min(((float)targetWidth), ((float)targetHeight)) / 2), paint);
            } catch (IOException e) {
            	// TODO Auto-generated catch block
            	e.printStackTrace();
            }

            return targetBitmap;
        }

        @Override
        protected void onPostExecute(final Bitmap result) {
        	int i = friends.size()-1;
			final float x = random.nextFloat() * CAMERA_WIDTH;
			final float y = random.nextFloat() * CAMERA_HEIGHT;	
			BitmapTextureAtlas texture = new BitmapTextureAtlas(getTextureManager(), result.getWidth(), result.getHeight(), TextureOptions.BILINEAR);
			final IBitmapTextureAtlasSource baseTextureSource = new EmptyBitmapTextureAtlasSource(result.getWidth(), result.getHeight());
			final IBitmapTextureAtlasSource decoratedTextureAtlasSource = new BaseBitmapTextureAtlasSourceDecorator(baseTextureSource) {

				@Override
				public BaseBitmapTextureAtlasSourceDecorator deepCopy() {
					throw new DeepCopyNotSupportedException();
				}

				@Override
				protected void onDecorateBitmap(Canvas pCanvas)
						throws Exception {
					pCanvas.drawBitmap(result, 0, 0, this.mPaint);
				}
				
			};

			ITextureRegion region = BitmapTextureAtlasTextureRegionFactory.createFromSource(texture, decoratedTextureAtlasSource, 0, 0);
			texture.load();
			final Sprite pic = new Sprite(x, y, region, getVertexBufferObjectManager()) {

				@Override
				public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
					Vibrator v;
					switch(pSceneTouchEvent.getAction()) {
						case TouchEvent.ACTION_DOWN:
							Friend friend;
							Friend oldFriend;
							friend = sprites.get(this);
							oldFriend = sprites.get(currentlySelected);
							ArrayList<Line> edges;
							System.out.println(socialNetwork.containsEdge(oldFriend,friend) + " " + socialNetwork.containsEdge(friend,oldFriend));
							if((socialNetwork.containsEdge(oldFriend,friend) || socialNetwork.containsEdge(friend,oldFriend)) && !(subGraph.containsEdge(friend,oldFriend) || subGraph.containsEdge(oldFriend,friend))) {	
								if(!subGraph.containsVertex(friend))
									subGraph.addVertex(friend);
								if(!subGraph.containsVertex(oldFriend))
									subGraph.addVertex(oldFriend);
								subGraph.addEdge(oldFriend, friend);
								CycleDetector<Friend,DefaultEdge> cd = new CycleDetector<Friend, DefaultEdge>(subGraph);
								
								currentlySelected.setScale(1.0f);
								selected.add(socialNetwork.getEdge(oldFriend, friend));
								selected.add(socialNetwork.getEdge(friend,oldFriend));
								currentlySelected = this;
								this.setScale(1.25f);
								friend = sprites.get(this);
								edges = friend.getEdges();
								for(Line e : edges) {
									if(!selected.contains(linesToEdge.get(e))) {
										e.setVisible(true);
										e.setColor(Color.BLACK);
									}
								}
								
								edges = oldFriend.getEdges();
								for(Line e : edges) {
									DefaultEdge edge1 = linesToEdge.get(e);
									if(selected.contains(edge1)) {
										e.setColor(Color.RED);
										selectedLines.add(e);
									}
									else
										e.setVisible(false);
								}
								if(cd.detectCycles()) {
									Set<Friend> cycle = cd.findCycles();
									subGraph = new DefaultDirectedGraph<Friend,DefaultEdge>(DefaultEdge.class);
									SocialNetworkActivity.this.score += (cycle.size())*100;
									for(Line l : selectedLines) {
										if(!l.isDisposed()) {
											DefaultEdge e = linesToEdge.get(l);
											Friend a = socialNetwork.getEdgeSource(e);
											Friend b = socialNetwork.getEdgeTarget(e);
											if(cycle.contains(a) && cycle.contains(b)) {
												socialNetwork.removeEdge(e);
												socialNetwork.removeEdge(b,a);
												a.removeEdge(l);
												b.removeEdge(l);
												linesToEdge.remove(l);
												scene.detachChild(l);
												l.dispose();
												l.detachSelf();
											}
											else {
												l.setColor(Color.BLACK);
											}
										} 
									}
									selectedLines.clear();
									selected.clear();
									mHandler.post(new Runnable() {
						                @Override
						                public void run() {
						                	Toast.makeText(SocialNetworkActivity.this, "Cycle Detected", Toast.LENGTH_LONG).show();
						                }
									});
									v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
			                        v.vibrate(300);
			                        SocialNetworkActivity.this.cycleFoundSound.play();
									return true;
									
								}
							} else {
								System.out.println("hi");
								if(currentlySelected != null)
									currentlySelected.setScale(1.0f);
								subGraph = new DefaultDirectedGraph<Friend,DefaultEdge>(DefaultEdge.class);
								selected.clear();
								currentlySelected = this;
								this.setScale(1.25f);
								friend = sprites.get(this);
								if(friend == null)
									friend = me;
								edges = friend.getEdges();
								for(int i = 0; i < scene.getChildCount(); i++) {
									IEntity entity = scene.getChild(i);
									if(entity.getClass().getName().equals("org.andengine.entity.primitive.Line"))
									{
										Line line = (Line) entity;
										line.setVisible(false);
									}
								}
								for(Line edge : edges) {
									edge.setVisible(true);
									edge.setColor(Color.BLACK);
								}
								
							}
							v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
	                        v.vibrate(300);
	                        SocialNetworkActivity.this.mFacebookPopSound.play();
							break;
					}
					return true;
				}
			};
			for(Friend friend : friends.values()) {
				while(pic.collidesWith(friend.getPicture()) || pic.collidesWith(me.getPicture())) {
					pic.setPosition(random.nextFloat()*2000, random.nextFloat()*1000);	
				}
			}
			Friend friend = new Friend(pic,uid);
			synchronized(friends) {
				friends.put(uid,friend);
			}
			synchronized(sprites) {
				sprites.put(pic, friend);
			}
			synchronized(friendToPic) {
				friendToPic.put(friend,new SoftReference<Bitmap>(result));
			}
			synchronized(socialNetwork) {
				socialNetwork.addVertex(friend);
				System.out.println(me.getId() + " " + friend.getId());
				socialNetwork.addEdge(me, friend);
				socialNetwork.addEdge(friend, me);
			}
			if(friends.size() == totalFriends) {
				connectStuff();
			}
			scene.registerTouchArea(pic);
			backLayer.attachChild(pic);    
        }
    }
    
    /*
     * Async Task to get my profile pic
     */
    private class GetMyPicAsyncTask extends AsyncTask<Object, Void, Bitmap> {
  
        @Override
        protected Bitmap doInBackground(Object... params) {
        	//Best place to do it
            JSONObject json;
			try {
				json = new JSONObject(Utility.mFacebook.request(player));
	            String userId = json.getString("id");
	            myId = userId;
			} catch (MalformedURLException e2) {
				// TODO Auto-generated catch block
				e2.printStackTrace();
			} catch (JSONException e2) {
				// TODO Auto-generated catch block
				e2.printStackTrace();
			} catch (IOException e2) {
				// TODO Auto-generated catch block
				e2.printStackTrace();
			}

            
        	Bitmap mBitmap = null;
            final String url = (String) params[0];
            URL img_value = null;
            try {
            	img_value = new URL(url);
            } catch (MalformedURLException e1) {
            	// TODO Auto-generated catch block
            	e1.printStackTrace();
            }
            Bitmap targetBitmap = null;
            try {
            	mBitmap = BitmapFactory.decodeStream(img_value.openConnection().getInputStream());
                int targetWidth = 100;
                int targetHeight = 100;
                targetBitmap = Bitmap.createBitmap(
                    targetWidth,
                    targetHeight,
                    Bitmap.Config.ARGB_8888);
                Canvas canvas = new Canvas(targetBitmap);
                final Paint paint = new Paint();
                paint.setStrokeWidth(10);
                paint.setStyle(Paint.Style.STROKE);
                paint.setColor(android.graphics.Color.GRAY);
                paint.setAntiAlias(true);
                paint.setDither(true);
                Path path = new Path();
                path.addCircle(
                    ((float)targetWidth - 1) / 2,
                    ((float)targetHeight - 1) / 2,
                    (Math.min(((float)targetWidth), ((float)targetHeight)) / 2),
                    Path.Direction.CCW);
                canvas.clipPath(path);
                canvas.drawBitmap(
                    mBitmap,
                    new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight()),
                    new Rect(0, 0, targetWidth, targetHeight),
                    null);
                canvas.drawCircle(((float)targetWidth - 1) / 2,
                        ((float)targetHeight - 1) / 2,
                        (Math.min(((float)targetWidth), ((float)targetHeight)) / 2), paint);
            } catch (IOException e) {
            	// TODO Auto-generated catch block
            	e.printStackTrace();
            }

            return targetBitmap;
        }

        @Override
        protected void onPostExecute(final Bitmap result) {
			final float x = CAMERA_WIDTH/2.0f - result.getWidth()/2.0f;
			final float y = CAMERA_HEIGHT/2.0f - result.getHeight()/2.0f;	
			
			BitmapTextureAtlas texture = new BitmapTextureAtlas(getTextureManager(), result.getWidth(), result.getHeight(), TextureOptions.BILINEAR);
			final IBitmapTextureAtlasSource baseTextureSource = new EmptyBitmapTextureAtlasSource(result.getWidth(), result.getHeight());
			final IBitmapTextureAtlasSource decoratedTextureAtlasSource = new BaseBitmapTextureAtlasSourceDecorator(baseTextureSource) {

				@Override
				public BaseBitmapTextureAtlasSourceDecorator deepCopy() {
					throw new DeepCopyNotSupportedException();
				}

				@Override
				protected void onDecorateBitmap(Canvas pCanvas)
						throws Exception {
					pCanvas.drawBitmap(result, 0, 0, this.mPaint);
				}
				
			};

			ITextureRegion region = BitmapTextureAtlasTextureRegionFactory.createFromSource(texture, decoratedTextureAtlasSource, 0, 0);
			texture.load();
			Sprite pic = new Sprite(x, y, region, getVertexBufferObjectManager()) {
				@Override
				public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
					Vibrator v;
					switch(pSceneTouchEvent.getAction()) {
					case TouchEvent.ACTION_DOWN:
						Friend friend;
						Friend oldFriend;
						friend = sprites.get(this);
						oldFriend = sprites.get(currentlySelected);
						ArrayList<Line> edges;
						if((socialNetwork.containsEdge(oldFriend,friend) || socialNetwork.containsEdge(friend,oldFriend)) && !(subGraph.containsEdge(friend,oldFriend) || subGraph.containsEdge(oldFriend,friend))) {	
							if(!subGraph.containsVertex(friend))
								subGraph.addVertex(friend);
							if(!subGraph.containsVertex(oldFriend))
								subGraph.addVertex(oldFriend);
							subGraph.addEdge(oldFriend, friend);
							CycleDetector<Friend,DefaultEdge> cd = new CycleDetector<Friend, DefaultEdge>(subGraph);
							
							currentlySelected.setScale(1.0f);
							selected.add(socialNetwork.getEdge(oldFriend, friend));
							selected.add(socialNetwork.getEdge(friend,oldFriend));				
							currentlySelected = this;
							this.setScale(1.25f);
							//this.mGrabbed = true;
							friend = sprites.get(this);
							edges = friend.getEdges();
							for(Line e : edges) {
								if(!selected.contains(linesToEdge.get(e))) {
									e.setVisible(true);
									e.setColor(Color.BLACK);
								}
							}
							
							edges = oldFriend.getEdges();
							for(Line e : edges) {
								DefaultEdge edge1 = linesToEdge.get(e);
								if(selected.contains(edge1)) {
									e.setColor(Color.RED);
									selectedLines.add(e);
								}
								else
									e.setVisible(false);
							}
							
							if(cd.detectCycles()) {
								Set<Friend> cycle = cd.findCycles();
								SocialNetworkActivity.this.score += (cycle.size())*100;
								subGraph = new DefaultDirectedGraph<Friend,DefaultEdge>(DefaultEdge.class);

								for(Line l : selectedLines) {
									if(!l.isDisposed()) {
										DefaultEdge e = linesToEdge.get(l);
										Friend a = socialNetwork.getEdgeSource(e);
										Friend b = socialNetwork.getEdgeTarget(e);
										if(cycle.contains(a) && cycle.contains(b)) {
											socialNetwork.removeEdge(e);
											socialNetwork.removeEdge(b,a);
											a.removeEdge(l);
											b.removeEdge(l);
											linesToEdge.remove(l);
											scene.detachChild(l);
											l.dispose();
											l.detachSelf();
										}
										else {
											l.setColor(Color.BLACK);
										}
									} 
								}
								selectedLines.clear();
								selected.clear();
								mHandler.post(new Runnable() {
					                @Override
					                public void run() {
					                	Toast.makeText(SocialNetworkActivity.this, "Cycle Detected", Toast.LENGTH_LONG).show();
					                }
								});
								v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
		                        v.vibrate(300);
		                        SocialNetworkActivity.this.cycleFoundSound.play();
								return true;
							}
						} else {
							if(currentlySelected != null)
								currentlySelected.setScale(1.0f);
							subGraph = new DefaultDirectedGraph<Friend,DefaultEdge>(DefaultEdge.class);
							selected.clear();
							currentlySelected = this;
							this.setScale(1.25f);
							//this.mGrabbed = true;
							friend = sprites.get(this);
							if(friend == null)
								friend = me;
							edges = friend.getEdges();
							for(int i = 0; i < scene.getChildCount(); i++) {
								IEntity entity = scene.getChild(i);
								if(entity.getClass().getName().equals("org.andengine.entity.primitive.Line"))
								{
									Line line = (Line) entity;
									line.setVisible(false);
								}
							}
							for(Line edge : edges) {
								edge.setVisible(true);
								edge.setColor(Color.BLACK);
							}
							
						}
						v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
						v.vibrate(300);
						SocialNetworkActivity.this.mFacebookPopSound.play();
						break;
					}
					return true;
				}
			};
			me = new Friend(pic,myId);
			synchronized(friendToPic) {
				friendToPic.put(me,new SoftReference<Bitmap>(result));
			}
			synchronized(sprites) {
				sprites.put(pic, me);
			}
			synchronized(socialNetwork) {
				socialNetwork.addVertex(me);
			}
			scene.registerTouchArea(pic);
			backLayer.attachChild(pic);  
        }
    }

    
    private class ProgressThread extends Thread {
    	Handler mHandler;
    	final static int STATE_DONE = 0;
    	final static int STATE_RUNNING = 1;
    	int mState;
    	int total = 0;
    	
    	ProgressThread(Handler h) {
    		this.mHandler = h;
    	}
    	
    	public void run() {
    		mState = STATE_RUNNING;
    		SocialNetworkActivity.this.mHandler.post(new Runnable() {

				@Override
				public void run() {
					// TODO Auto-generated method stub
	    			requestUserData();
				}
    		});
    		
    		while(mState == STATE_RUNNING) {
    			Message msg = mHandler.obtainMessage();
    			msg.arg1 = mState;
    			mHandler.sendMessage(msg);
    			this.total = progressDialog.getProgress();
    			if(everythingLoaded)
    				mState = STATE_DONE;
    		}
    	}
    	
    	public void setState(int state) {
    		mState = state;
    	}
    }


}
